package com.joy.joyusers.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.joy.joyusers.common.ErrorCode;
import com.joy.joyusers.excption.BusinessException;
import com.joy.joyusers.mapper.TeamMapper;
import com.joy.joyusers.model.VO.TeamUserVO;
import com.joy.joyusers.model.VO.UserVO;
import com.joy.joyusers.model.domain.Team;
import com.joy.joyusers.model.domain.User;
import com.joy.joyusers.model.domain.UserTeam;
import com.joy.joyusers.model.dto.TeamQuery;
import com.joy.joyusers.model.enums.TeamStatusEnum;
import com.joy.joyusers.model.request.TeamJoinRequest;
import com.joy.joyusers.model.request.TeamQuitRequest;
import com.joy.joyusers.model.request.TeamUpdateRequest;
import com.joy.joyusers.service.TeamService;
import com.joy.joyusers.service.UserService;
import com.joy.joyusers.service.UserTeamService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
* @author 40919
* @description 针对表【team(队伍)】的数据库操作Service实现
* @createDate 2024-05-14 17:59:18
*/
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
    implements TeamService {

    @Resource
    private UserTeamService userTeamService;

    @Resource
    private UserService userService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public long addTeam(Team team, User loginUser) {
        //  1. 请求参数是否为空？
        if (team == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //  2. 是否登录，未登录不允许创建
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        final long userId = loginUser.getId();
        //  3. 校验信息
        //   1. 队伍人数 > 1 且 <= 20
        int maxNum = Optional.ofNullable(team.getMaxNum()).orElse(0);  // 如果为空设置默认值为0
        System.out.println("队伍人数设置" + maxNum);
        if (maxNum < 1 || maxNum > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数不合法");
        }
        //   2. 队伍标题 <= 20
        String name = team.getName();
        if (StringUtils.isBlank(name) || name.length() > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍标题不合法");
        }
        //   3. 描述 <= 512
        String description = team.getDescription();
        if (StringUtils.isBlank(description) && description.length() > 512) {      // 不为空并且大于512
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍描述不合法");
        }
        //   4. status 是否公开（int）不传默认为 0（公开）
        int status = Optional.ofNullable(team.getStatus()).orElse(0);
        TeamStatusEnum teamStatusEnum = TeamStatusEnum.getTeamStatusEnum(status); // 获取枚举值
        if (teamStatusEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍状态不合法");
        }
        //   5. 如果 status 是加密状态，一定要有密码，且密码 <= 32
        String password = team.getPassword();
        if (TeamStatusEnum.SECRET.equals(teamStatusEnum) && (StringUtils.isBlank(password) || password.length() > 32)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "加密状态下必须设置密码，且密码 <= 32");
        }
        //   6. 超时时间 > 当前时间
        Date expireTime = team.getExpireTime();
        if (new Date().after(expireTime)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍过期时间大于当前时间");
        }
        //   7. 校验用户最多创建 5 个队伍
        QueryWrapper<Team> queryWrapper = new QueryWrapper<Team>();
        queryWrapper.eq("user_id", userId);
        long hasTeamNum = this.count(queryWrapper);
        if (hasTeamNum >= 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户最多创建 5 个队伍");
        }

        //   8. 插入队伍信息到队伍表
        team.setId(null);            // id是自增的
        team.setUserId(userId);
        boolean saveResult = this.save(team);
//        if (true) { // 测试事务用的，成功了
//            throw new BusinessException(ErrorCode.PARAMS_ERROR,"插入队伍信息到队伍表失败");
//        }
        if (!saveResult || team.getId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"插入队伍信息到队伍表失败");
        }
        //   9. 插入用户  => 队伍关系到关系表
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(userId);
        userTeam.setTeamId(team.getId());
        userTeam.setJoinTime(new Date());
        // 调用队伍用户服务插入
        boolean saveTeamResult = userTeamService.save(userTeam);
        if (!saveTeamResult) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"创建队伍");
        }
        return team.getId();
    }

    /**
     * 查询队伍列表
     * @param teamQuery 查询参数对象
     * @param isAdmin 当前登录用户
     * @return
     */
    @Override
    public List<TeamUserVO> listTeam(TeamQuery teamQuery, boolean isAdmin) {
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        if (teamQuery != null) {
            // 队伍id
            Long id = teamQuery.getId();
            if (id != null && id>0) {
                queryWrapper.eq("id", id);
            }
            // 多个id查询的情况
            List<Long> idList = teamQuery.getIdList();
            if (CollectionUtils.isNotEmpty(idList)) {
                queryWrapper.in("id", idList);
            }
            // 获取搜索关键词
            String searchText = teamQuery.getSearchText();
            if (StringUtils.isNotBlank(searchText)) {
                queryWrapper.and(wq -> wq.like("name", searchText).or().like("description", searchText));
            }

            // 队伍名称
            String name = teamQuery.getName();
            if (StringUtils.isNotBlank(name)) {
                queryWrapper.like("name", name);
            }
            // 队伍描述
            String description = teamQuery.getDescription();
            if (StringUtils.isNotBlank(description)) {
                queryWrapper.like("description", description);
            }
            // 队伍最大人数
            Integer maxNum = teamQuery.getMaxNum();
            if (maxNum != null && maxNum>0) {
                queryWrapper.eq("max_num", maxNum);
            }
            //根据创建人id来查询
            Long userId = teamQuery.getUserId();
            if (userId != null && userId>0) {
                queryWrapper.eq("user_id", userId);
            }
            // 根据状态查询
            Integer status = teamQuery.getStatus();
            // 根据状态码获取队伍状态对象
            TeamStatusEnum teamStatusEnum = TeamStatusEnum.getTeamStatusEnum(status);
            if (status == null) {
                teamStatusEnum = TeamStatusEnum.PUBLIC;      // 没有就公开
            }
            if (!isAdmin && teamStatusEnum.equals(TeamStatusEnum.PUBLIC)) {               // 如果不是管理员，且是私有或者加密的队伍，则不展示
                throw new BusinessException(ErrorCode.NO_AUTH);
            }
            queryWrapper.eq("status", teamStatusEnum.getValue());

        }

        // 不展示过期队伍，或者就是在下面遍历里面处理过滤掉
        queryWrapper.and(qw -> qw.gt("expire_time", new Date()).or().isNull("expire_time"));


        // 终于判断完条件了, 查询队伍
        List<Team> list = this.list(queryWrapper);
        System.out.println("查询所有符合条件队伍");
        if (CollectionUtils.isEmpty(list)) {
            // 如果为空返回一个空数组
            return new ArrayList<>();
        }
        // 关联查询用户的信息
        // 自己写sql：1. select * from team t left join user u on t.user_id = u.id
        // 查询队伍和已加入队伍的成员的信息
        // select * from team t left join user_team on t.id = user_team.team_id

        List<TeamUserVO> teamUserVOList = new ArrayList<>();
        // 先查询关联创建人吧，先不关联加入的用户了, todo: 关联创始人看不到其他队伍，只能看自己创建的
        for (Team team : list) {
            System.out.println("遍历队伍");
            System.out.println(team.toString());
            Long userId = team.getUserId();
            if ( userId == null ) {
                continue;
            }
            User createUser = userService.getUserById(userId);
            // TeamUserVO其实就是包含创建人对象的 《返回封装》
            TeamUserVO teamUserVO = new TeamUserVO();
            // 参数1：要复制的对象
            // 参数2： 赋值给他的对象
            BeanUtils.copyProperties(team, teamUserVO);
            // 数据脱敏
            if (createUser != null) {
                UserVO userVO = new UserVO();
                BeanUtils.copyProperties(createUser, userVO);
                // 设置队伍的创建人信息
                teamUserVO.setCreateUser(userVO);
            }

            teamUserVOList.add(teamUserVO);
        }

        return teamUserVOList;
    }

    /**
     * 更新队伍
     * @param team 查询参数的封装
     * @param loginUser 登录的用户信息
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateTeam(TeamUpdateRequest team, User loginUser) {
        // 判断查询数据是否为空
        if (team == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 从team查询参数中获取team_id，
        Long id = team.getId();
        if (id == null || id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 查询出要修改的team
        Team oldTeam = this.getById(id);
        if (oldTeam == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "修改的队伍不存在");
        }
        // 如果登录用户不是队伍的创建者，并且也不是管理员
        if (oldTeam.getUserId() != loginUser.getId() && !userService.isAdmin(loginUser)) {
            throw new BusinessException(ErrorCode.NO_AUTH);
        }
        // 加个校验，如果队伍是加密的，那么必须有密码
        TeamStatusEnum teamStatusEnum = TeamStatusEnum.getTeamStatusEnum(team.getStatus());
        if (teamStatusEnum.equals(TeamStatusEnum.SECRET)) {
            if (StringUtils.isBlank(team.getPassword())){
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码不能为空");
            }
        }

        Team updateTeam = new Team();
        BeanUtils.copyProperties(team, updateTeam); // 把参数给新建的team对象
        return this.updateById(updateTeam);

    }

    /**
     * 登录用户加入队伍
     * @param teamJoinRequest 加入队伍参数
     * @param loginUser 当前登录用户
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean joinTeam(TeamJoinRequest teamJoinRequest, User loginUser) {
        // 判断查询数据是否为空
        if (teamJoinRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数错误");
        }
        // 判断当前是否是登录用户加入队伍的
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数错误");
        }

        // 获取队伍id
        Long teamId = teamJoinRequest.getId();
        // 查询队伍是否存在
        Team team = getTeamById(teamId);

        // 判断队伍是否过期
        Date expireTime = team.getExpireTime();
        if (expireTime != null && expireTime.before(new Date()))  {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍已过期");
        }
        // 不允许加入私有的队伍
        Integer status = team.getStatus();
        TeamStatusEnum teamStatusEnum = TeamStatusEnum.getTeamStatusEnum(status);
        if (TeamStatusEnum.PRIVATE.equals(teamStatusEnum)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "禁止加入私有队伍");
        }
        // 如果队伍是加密的，那就必须输入密码和队伍密码是相等的
        String password = teamJoinRequest.getPassword();
        if (TeamStatusEnum.SECRET.equals(teamStatusEnum)) {
            if (StringUtils.isBlank(password) || !password.equals(team.getPassword())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");
            }
        }
        // 先判断不需要查询数据库的校验，
        // 用户最多加入5个队伍
        long userId = loginUser.getId();
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        // 查询队伍用户关系表里面，user_id的用户到底关联了几个队伍信息
        queryWrapper.eq("user_id", userId);
        long hasJoinCount = userTeamService.count(queryWrapper);
        if (hasJoinCount >= 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户最多加入5个队伍");
        }

        // 用户不能加入已经加入的队伍, 直接用两个id去查询关系表就好了，有没有就知道是否已经加入了
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("team_id", teamId);
        long hasUserJoinTeam = userTeamService.count(queryWrapper);
        if (hasUserJoinTeam > 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "已经加入的队伍");
        }

        // 校验用户只能加入未满的队伍
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("team_id", teamId);
        Long teamHasJoinNum = userTeamService.count(queryWrapper); // 查询队伍的人数就行
        if (teamHasJoinNum >= team.getMaxNum()) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "队伍已满");
        }

        // 最后添加关联信息就好了，就是用户加入队伍了
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(userId);
        userTeam.setTeamId(teamId);
        userTeam.setJoinTime(new Date());
        boolean saveResult = userTeamService.save(userTeam);

        return saveResult;
    }

    /**
     * 用户退出队伍
     * @param teamQuitRequest 要退出的队伍信息
     * @param loginUser 登录用户
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean quitTeam(TeamQuitRequest teamQuitRequest, User loginUser) {
        // 校验参数
        if (teamQuitRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 拿到要退出的队伍id
        Long teamId = teamQuitRequest.getId();
        Team team = getTeamById(teamId);
        // 校验登录用户是否加入队伍, 查询条件构造器传入一个UserTeam对象就行了
        long userId = loginUser.getId();
        UserTeam queryUserTeam = new UserTeam();
        queryUserTeam.setTeamId(teamId);
        queryUserTeam.setUserId(userId);
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>(queryUserTeam);
        long count = userTeamService.count(queryWrapper);
        if (count == 0) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "未加入队伍");
        }
        // 获取队伍已加入人数
        Long teamHasJoinNum = getTeamUserCountbyTeamId(teamId);

        // 队伍只剩下一人了，删除队伍和用户队伍关联表
        if (teamHasJoinNum == 1) {
            this.removeById(teamId);    // 删除队伍
            // 删除所有队伍关系
//            QueryWrapper<UserTeam> queryTeamNum = new QueryWrapper<>();
//            queryWrapper.eq("team_id", teamId);
//            boolean remove = userTeamService.remove(queryTeamNum);
//            return remove;
        }else{
            // 如果是队长
            // 队伍至少有两人退出队伍的情况
            if (team.getUserId() == userId){
                // 把创建人转移给最早加入的用户，要查询判断一下第二早是谁
                // 1. 查询已加入的队伍的所有用户和加入时间
                QueryWrapper<UserTeam> userTeamqueryWrapper = new QueryWrapper<>();
                userTeamqueryWrapper.eq("team_id", teamId);
                userTeamqueryWrapper.last("order by id asc limit 2");    // 根据id排序，然后取两条
                List<UserTeam> userTeamlist = userTeamService.list(userTeamqueryWrapper);
                // 参数校验
                if (CollectionUtils.isEmpty(userTeamlist) || userTeamlist.size() <= 1) {  // 只有一个人在队伍里面抛出异常
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR);
                }
                // 获取队伍排完序的第二个用户，下表为1，下表为0一定是队长对吧
                UserTeam nextUserTeam = userTeamlist.get(1);
                Long nextLeaderId = nextUserTeam.getUserId();
                Team updateTeam = new Team();
                updateTeam.setUserId(nextLeaderId);
                updateTeam.setId(teamId);
                // 更新队伍信息
                boolean result = this.updateById(updateTeam);
                if (!result) { // 更新失败
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR);
                }
                // 如果都不是队长，或者不是最后一个退出队伍，就单纯删除关系就好
                userTeamqueryWrapper = new QueryWrapper<>();
                userTeamqueryWrapper.eq("team_id", teamId);
                userTeamqueryWrapper.eq("user_id", userId);
                // 删除用户队伍关系
                boolean remove = userTeamService.remove(userTeamqueryWrapper);
                return remove;
            }
        }
        // 不是队长呢
        return userTeamService.remove(queryWrapper);
    }

    /**
     * 获取队伍信息，检测队伍是否存在
     * @param teamId 队伍id
     * @return
     */
    private Team getTeamById(Long teamId) {
        System.out.println("teamId = " + teamId);
        if (teamId == null || teamId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 判断队伍是否存在
        Team team = this.getById(teamId);
        if (team == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "队伍不存在");
        }
        return team;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteTeam(long id, User loginUser) {
        // 1. 判断队伍是否存在
        Team team = getTeamById(id);
        long teamId = team.getId();    // 队伍id
        // 2. 校验是否为队伍队长
        if (team.getUserId() != loginUser.getId()) {
            throw new BusinessException(ErrorCode.NO_AUTH, "没有权限解散队伍");
        }
        // 3. 移除队伍的关联信息
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("team_id", teamId);
        boolean result = userTeamService.remove(queryWrapper);
        if (!result) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除队伍关联信息失败");
        }
        // 4. 删除所有队伍
        return this.removeById(teamId);

    }

    /**
     * 获取队伍加入的人数
     * @param teamId
     * @return
     */
    private Long getTeamUserCountbyTeamId(Long teamId) {
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("team_id", teamId);
        Long teamHasJoinNum = userTeamService.count(queryWrapper); // 查询队伍的人数就行
        return teamHasJoinNum;
    }
}




